import { Injectable, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as Minio from 'minio';
import { BufferedFile } from './file.model';
import { ImageUtil } from '../utils/image.util';

@Injectable()
export class MinioService implements OnModuleInit {
  private minioClient: Minio.Client;
  private readonly bucketName: string;

  constructor(private readonly configService: ConfigService) {
    ImageUtil.init(configService);
    this.bucketName = this.configService.get(
      'COMMUNITY_IMAGE_BUCKET',
      'community-images',
    );

    this.minioClient = new Minio.Client({
      endPoint: this.configService.get('MINIO_ENDPOINT', 'localhost'),
      port: Number(this.configService.get('MINIO_PORT', 9000)),
      useSSL: this.configService.get('MINIO_USE_SSL', 'false') === 'true',
      accessKey: this.configService.get('MINIO_ACCESS_KEY', 'minioadmin'),
      secretKey: this.configService.get('MINIO_SECRET_KEY', 'minioadmin'),
    });
  }

  async onModuleInit() {
    try {
      const bucketExists = await this.minioClient.bucketExists(this.bucketName);
      if (!bucketExists) {
        await this.minioClient.makeBucket(this.bucketName, 'us-east-1');
        // 设置存储桶策略为公共读取
        const policy = {
          Version: '2012-10-17',
          Statement: [
            {
              Effect: 'Allow',
              Principal: { AWS: ['*'] },
              Action: ['s3:GetObject'],
              Resource: [`arn:aws:s3:::${this.bucketName}/*`],
            },
          ],
        };
        await this.minioClient.setBucketPolicy(
          this.bucketName,
          JSON.stringify(policy),
        );
      }
    } catch (err) {
      console.error('Error initializing MinIO bucket:', err);
      throw err;
    }
  }

  async upload(file: BufferedFile, basePath = ''): Promise<string> {
    const timestamp = Date.now();
    const filename = `${basePath}${timestamp}-${file.originalname}`;
    const metaData = {
      'Content-Type': file.mimetype,
    };

    try {
      await this.minioClient.putObject(
        this.bucketName,
        filename,
        file.buffer,
        file.size,
        metaData,
      );

      // 返回相对路径
      return `${this.bucketName}/${filename}`;
    } catch (err) {
      console.error('Error uploading file to MinIO:', err);
      throw err;
    }
  }

  async delete(filename: string): Promise<void> {
    try {
      // 从完整 URL 中提取相对路径
      const relativePath = ImageUtil.getRelativePath(filename);
      const [bucketName, ...pathParts] = relativePath.split('/');
      const objectName = pathParts.join('/');

      await this.minioClient.removeObject(bucketName, objectName);
    } catch (err) {
      console.error('Error deleting file from MinIO:', err);
      throw err;
    }
  }
}
